/**
 * @author Austin Andrews (Templarian)
 * @authorurl http://templarian.com
 * @framework DD Framework
 * @licence New BSD License
 * @licenceurl http://ddframework.googlecode.com/svn/trunk/license.txt
 * @overview Core
 */
/**
 * Use as a function or to access properties
 * @namespace dd
 * @property
 *  Access modules and core functionality
 * @function
 *  Select a dom element by id attribute
 *  @param id {string} An id attribute of a visible dom element
 *  @returns dd.fn
 * @function
 *  Select a dom element by passing an object
 *  @param element {object} DOM elment
 *  @returns dd.fn
 * @function
 *  Select multiple dom objects by passing an array
 *  @param element {array} Array of DOM elments or IDs
 *  @returns dd.fn
 * @function
 *  Create an anonymous function with a new scope
 *  @param func {function} Function to bind the scope to
 *  @param scope {object} Variables to bind to `this` in func
 *  @returns dd.fn
 *  "Anonymous Function"[javascript]@@
 *  var aFunc = dd(function(hello){
 *      alert(this.foo); // "bar"
 *      alert(hello); // "world"
 *  }, {foo:"bar"});
 *  aFunc("world");
 *  @@
 * @function
 *  Configure framework for use.
 *  @param config {object}
 *  "Config"[javascript]@@
 *  dd({
 *      modules:[           // Array of modules to load
 *          "http"         // File `dd/dd.http.js`
 *      ],
 *      projects:{          // List of projects
 *          app:[           // Array of app's files
 *              "ui"        // File, `app/app.ui.js`
 *          ]           
 *      }
 *  });
 *  @@
 */
var dd = function(o1, o2)
{
    return dd.is(o2)
        ? function()
        {
            dd.combine(this, o2);
            o1.apply(this, arguments);
        }
        : typeof o1 == "string"
            ? new dd.selector(o1) // Selector String
            : "self" in o1
                ? "fn" in o1.self
                    ? new o1.self.fn(o1) // Custom Control
                    : new dd.fn(o1) // Element
                : dd._c.call(dd, o1); // Config / Empty
};
/**
 * Create reserved properties
 */
dd.ns = ["dd"];
dd._o = {};
dd._a = {};
/**
 * Construct a usable object scope for objects
 */
dd.fn = function(o)
{
    // Replace this with the http://sizzlejs.com/ Selector Engine
    this.self = o.self;
};
/**
 * is
 * @namespace dd.is
 * @function
 *  Check if variable is Undefined
 *  @param value {} Value to check
 *  @param type {string} Type to check against
 *  @returns element
 * @function
 *  Check if key is in object
 *  @param key {} Key
 *  @param object {string} Object
 *  @returns element
 */
dd.is = function(v, t)
{
    var _v = v instanceof Array ? "array" : typeof(v);
    var _t = t instanceof Array ? "array" : typeof(t);
    if(_t === "undefined")
    {
        return v === null ? false : _v !== "undefined";
    }
    else if(_t === "string")
    {
        return _v === t;
    }
    else if(_t === "array")
    {
        //if(this._a !== t)
        //{
            this._o = {};
            for(var i = 0; i < t.length; i++)
            {
                this._o[t[i]] = null;
            }
            //this._a = t;
        //}
        return v in this._o;
    }
    else if(_v === "array")
    {
        for(var i = 0; i < v.length; i++)
        {
            if(v[i] in t)
            {
                return true;
            }
        }
        return false;
    }
    else if(_t == "object")
    {
        return typeof(t[v]) !== "undefined";
    }
    alert("Error: dd.is");
    return false;
};
/*
 * Compatiblity fix for JS 1.8.5
 */
try
{
    if(!Object.prototype.__defineGetter__ && Object.defineProperty({},"x",{get:function(){return true}}).x)
    {
        Object.defineProperty(Object.prototype,"__defineGetter__",{enumerable:false,configurable:true,value:function(name,func){Object.defineProperty(this,name,{get:func,enumerable:true,configurable:true});}});
        Object.defineProperty(Object.prototype,"__defineSetter__",{enumerable:false,configurable:true,value:function(name,func){Object.defineProperty(this,name,{set:func,enumerable:true,configurable:true});}});
    }
}catch(e){};
/*
 * @namespace dd.combine
 * @function
 *  Combine a second object into the first object
 *  @param object1 {object} The object to be extended
 *  @param object2 {object} The object to be extended into the first
 *  @returns new result of placing object1 into object2.
 *  "Combining Two Objects"[javascript]@@
 *  var obj1 = {foo:"bar"};
 *  var obj2 = {hello:"world"};
 *  {foo:"bar", hello:"world"} == dd.combine(obj1, obj2);
 *  @@
 * @function
 *  Overload allowing ignoring of properties
 */
dd.combine = function(o1, o2, o3, o4)
{
    if(!dd.is(o2))
    {
        alert("Error: dd.combine");
        return false;
    }
    o4 = typeof(o3) == "boolean" ? o3 : o4 || false;
    o3 = typeof(o3) == "object" ? o3 : {};
    o1 = o4 ? o1.prototype : o1;
    // Modern, Fallback to legacy.
    if(Object.defineProperty)
    {
        for(var i in o2)
        {
            if(!(i in o3))
            {
                var d = Object.getOwnPropertyDescriptor(o2, i);
                Object.defineProperty(o1, i, d);
            }
        }
    }
    else
    {
        for(var i in o2)
        {
            if(!(i in o3))
            {
                var g = o2.__lookupGetter__(i),
                    s = o2.__lookupSetter__(i);
                if(g || s)
                {
                    if(g)
                    {
                        o1.__defineGetter__(i, g);
                    }
                    if(s)
                    {
                        o1.__defineSetter__(i, s);
                    }
                }
                else
                {
                    o1[i] = o2[i];
                }
            }
        }
    }
    return o1;
};
/**
 * Overloaded function to extend the framework
 * @namespace dd.extend
 * @function
 *  Extend the core of the framework
 *  @param obj {object} Ex:
 *  "Example"[javascript]@@
 *  {
 *      // Called on load
 *      init:function()
 *      {
 *          [...]
 *      },
 *      //module.submodule()
 *      func:function()
 *      {
 *          [...]
 *      }
 *  }
 *  @@
 * @function
 *  Define new modules included with the framework
 *  @param moduleName {string} Ex: "module.submodule"
 *  @param obj {object} Ex:
 *  "Example"[javascript]@@
 *  {
 *      // Called on load
 *      init:function()
 *      {
 *          [...]
 *      },
 *      //module.submodule()
 *      func:function()
 *      {
 *          [...]
 *      }
 *  }
 *  @@
 */
dd.extend = function(o1, o2)
{
    if(dd.is(o1, "string") && (!dd.is(o2) || dd.is(o2, "function")))
    {
        var e = /(.*?)([^\/]+)$/.exec(o1);
        var m = dd.nsToObj(this, e[2]);
        if("isInit" in m)
        {
            (o2 || function(){})();
            return true;
        }
        var isP = m.ns[1] == "project";
        var p = e[1] == ""
            ? (isP
                ? m.ns.length == 3
                    ? dd.path + m.ns[m.ns.length - 1] + "/"
                    : this.path
               : this.path + "dd/")
            : /http:\/\//.test(e[1]) || isP
                ? e[1]
                : /^~/.test(e[1])
                    ? e[1].match(/^~(.*)/)[1]
                    : this.path + e[1];
        m.extend({
            func:function(){alert("Error: No function defined");},
            isInit:false,
            isSetup:false,
            parent:this,
            path:p,
            source:p + (isP ? m.ns.slice(2) : m.ns).join(".") + ".js",
            cb:o2 || function(){}
        });
        dd.initLoad(m);
        return true;
    }
    else if((dd.is(o1, "string") || dd.is(o1, "array")) && dd.is(o2, "object"))
    {
        dd.nsToObj(this, o1).extend(o2);
    }
    else if((dd.is(o1, "object") || dd.is(o1, "function")) && dd.is(o2, "object"))
    {
        dd.combine(o1, o2, {fn:{}, dd:{}, window:{}}); // Ignore fn and dd
        if("fn" in o2)
        {
            dd.combine(dd.fn, o2.fn, true); // Enables Prototyping!
        }
        if("dd" in o2) //BUG: .func does not overwrite correctly... method() -> return this.func.apply(this, arguments)
        {
            dd.combine(dd, o2.dd);
        }
        if("window" in o2)
        {
            dd.combine(window, o2.window);
        }
    }
    else if(dd.is(o1, "object") && !dd.is(o2))
    {
        if("ns" in this)
        {
            dd.extend(this, o1);
        }
        else
        {
            dd.combine(this, o1);
        }
        return this;
    }
    return false;
};
/* Extend dd */
dd.extend({
    window:{self:{e:window}},
    document:{self:{e:document}},
    _loadOrder:[],
    _noWait:false,
    /**
     * Initiate loading of files
     * @namespace dd.initLoad
     */
    initLoad:function(o)
    {
        if(typeof(o) == "function")
        {
            dd._files.push(o);
            dd.addJS(o.source);
            if(!dd._isScanning)
            {
                dd.initLoad();
                dd._isScanning = true;
            }
        }
        else
        {
            for(var i = dd._fCount; i < dd._files.length; i++)
            {
                var m = dd._files[i];
                //console.log(m.ns.join("-") + ", body:" + ("body" in dd) + ", init:" + m.isInit + ", isSetup:" + m.isSetup);
                if((m.isSetup && !m.isInit && m.ns[1] != "project")
                    || (m.isSetup && !m.isInit && m.ns[1] == "project" && "body" in dd))
                {
                    dd._loadOrder.push(m.ns);
                    if("init" in m)
                    {
                        m.init.call(m);
                    }
                    m.isInit = true;
                    dd._fCount++;
                    m.cb.call(m);
                }
                else
                {
                    break;
                }
            }
            if(dd._fCount != dd._files.length || !("body" in dd))
            {
                setTimeout(dd.initLoad, 200);
            }
            else
            {
                dd._load.call({});
                dd._load = function(){};
                dd._isScanning = false;
            }
        }
        return true;
    },
    /**
     * Decode / Encode
     * Document this.
     */
    json:function(o)
    {
        if(typeof o == "string")
        {
            return JSON.parse(o);
        }
        else
        {
            return JSON.stringify(o);
        }
    },
    _isScanning:false,
    _fCount:0,
    _files:[],
    path:"scripts/",
    ready:false,
    get title()
    {
        return document.title;
    },
    set title(v)
    {
        return document.title = v;
    },
    head:{self:{e:document.getElementsByTagName("head")[0]}},
    _c:function(o)
    {
        // Undefined
        if(!dd.is(o))
        {
            alert("Error: dd(undefined)");
            return false;
        }
        // Empty Object
        var c = 0;
        for(var i in o)
        {
            c++;
        }
        if(c != 0 && !("modules" in o || "config" in o))
        {
            alert("Error: dd(object), invalid object");
            return false;
        }
        dd(dd.head).each(function(){
            if(this.nodeName == "script")
            {
                if(/dd\.js$/.test(this.src))
                {
                    dd.path = /(.*)dd\/dd\.js$/.exec(this.src)[1];
                }
            }
        });
        if("modules" in o)
        {
            for(var i in o.modules)
            {
                dd.extend(o.modules[i]);
            }
            dd._mCount = o.modules.length;
        }
        else
        {
            dd._noWait = true;
            if(dd._readied)
            {
                setTimeout(function(){dd._load();}, 1);
            }
        }
        if("projects" in o)
        {
            for(var i in o.projects)
            {
                this.project.extend(i);
                for(var j in o.projects[i])
                {
                    dd.nsToObj(dd.project, i).extend(o.projects[i][j]);
                }
            }
        }
        return {
            event:function(o, s)
            {
                s = s || {};
                dd._ready = "ready" in o
                    ? dd(function()
                    {
                        this.f.call(this.s);
                    }, {f:o.ready, s:s})
                    : function(){};
                dd._load = "load" in o
                    ? dd(function()
                    {
                        this.f.call(this.s);
                    }, {f:o.load, s:s})
                    : function(){};
            }
        };
    },
    _readied:false,
    _ready:function(){},
    _load:function(){},
    _loading:function(){},
    toL:function(s)
    {
        return dd.is(s) ? s.toLowerCase() : "";
    },
    toU:function(s)
    {
        return dd.is(s) ? s.toUpperCase() : "";
    },
    clone:function(a)
    {
        var b = [];
        for(var i in a)
        {
            b[i] = a[i];
        }
        return b;
    },
    /**
     * Trim whitespace
     * @namespace dd.trim
     * @function
     *  @param str {string} String to trim
     */
    trim:function(v)
    {
        return v.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
    },
    _fn:["event", "trigger"],
    fnF:function(r, j, t)
    {
        return function()
        {
            for(var i in r)
            {
                if(typeof(r[i].fn[j]) == "function")
                {
                    r[i].fn[j].apply(r[i].fn, arguments);
                }
            }
            return t;
        }
    },
    current: { project: null },
    selector: function() { dd.log("No selector library loaded.", "error"); },
    log:{
        func: function(message, level){},
        log:"log",
        error:"error"
    },
    /**
     * Function definition for dd
     * @namespace dd.fn
     * @property
     *  Stores all function calls for dd
    */
    fn:{
        get canvas()
        {
            return this.o[0].nodeName == "canvas" ? this.fn.e.getContext('2d') : null;
        },
        get value()
        {
            var e = this.self.e;
            return e.nodeValue == "checkbox"
                ? e.checked
                : e.value;
        },
        set value(v)
        {
            var e = this.self.e;
            return e.nodeValue == "checkbox"
                ? e.checked = v
                : e.value = v;
        },
        get lines()
        {
            var e = this.self.e;
            var l = 0;
            for(var i = 0; i < e.childNodes.length; i++)
            {
                if(e.childNodes[i].nodeName.toLowerCase() == "br")
                {
                    l++;
                }
            }
            return l;
        },
        get text()
        {
            var e = this.self.e;
            // Text | HTML | Empty
            return e.childNodes.length > 0
                    ? e.childNodes[0].nodeValue
                    : "";
        },
        set text(v)
        {
            var e = this.self.e;
            while(e.childNodes[0])
            {
                e.removeChild(e.childNodes[0]);
            }
            var p = v.toString().split(/\r?\n/);
            if(p.length == 1)
            {
                e.appendChild(document.createTextNode(p[0]));
            }
            else
            {
                for(var i in p)
                {
                    e.appendChild(document.createTextNode(p[i].replace(/ /g, "\u00a0")));
                    if(i != p.length - 1)
                    {
                        e.appendChild(document.createElement("br"));
                    }
                }
            }
            return v;
        },
        /**
         * Loop through an array of elements or objects
         * @namespace dd.fn.each
         * @function
         *  Loop through pass object to `this`
         *  @param func {function} Callback for loop
         * @function
         *  Loop through with custom scope
         *  @param func {function} Callback for loop
         *  @param scope {object} Variables to be passed into scope
         */
        each:function(f, s)
        {
            s = dd.is(s) ? s : {};
            var c = this.self.e.children;
            var r = [];
            for(var i = 0; i < c.length; i++)
            {
                if(dd.is(c[i]))
                {
                    var r = {
                        nodeName:c[i].nodeName.toLowerCase(),
                        self:c[i]
                    };
                    var a = c[i].attributes;
                    for(var j = 0; j < a.length; j++)
                    {
                        r[a[j].nodeName] = a[j].nodeValue;
                    }
                    dd.combine(r, s);
                    f.call(r);
                }
            }
        },
        /**
         * Adds text
         * @namespace dd.fn.addText
         * Document?
         */
        addText:function(text)
        {
            this.self.e.appendChild(document.createTextNode(text));
        },
        /**
         * Adds an element 
         * @namespace dd.fn.addElement
         * @function
         *  Add element to DOM
         *  @param name {string} Element name
         *  @returns {object} element
         * @function
         *  Add element to DOM
         *  @param name {string} Element name
         *  @param innerText {string} Inner text
         *  @returns element
         *  @function
         *  Add element to DOM
         *  @param name {string} Element name
         *  @param innerText {object} Attributes
         *  @returns {object} element
         * @function
         *  Add element to DOM
         *  @param name {string} Element name
         *  @param innerText {string} Inner text
         *  @param attributes {object} Attributes
         *  @returns {object} element
         * @function
         *  Add element to DOM
         *  @param namespace_name {object} Dom elment, ex: {"svg":"rect"}
         *  @returns {object} element
         * @function
         *  Add element to DOM
         *  @param namespace_name {object} Dom elment, ex: {"svg":"rect"}
         *  @param attribute {object} Attributes
         *  @returns {object} element
         * @function
         *  Add element to DOM
         *  @param namespace_name {object} Element name, ex: {"svg":"rect"}
         *  @param innerText {string} Inner text
         *  @param id {object} Attributes
         *  @returns {object} element
         */
        addElement:function(o1, o2, o3, o4)
        {
            var e = {};
            if(dd.is(o1, "string"))
            {
                e = document.createElement(o1);
            }
            else if(dd.is(o1, "object"))
            {
                for(var i in o1)
                {
                    e = document.createElementNS(dd._ns[i], i + ":" + o1[i]);
                }
            }
            if(dd.is(o2, "object"))
            {
                for(var j in o2)
                {
                    if(j == "class")
                    {
                        e.className = o2[j];
                    }
                    else
                    {
                        e.setAttribute(j, o2[j]);
                    }
                }
            }
            else if(dd.is(o2, "string") || dd.is(o2, "number"))
            {
                if(o2 != "")
                {
                    e.appendChild(document.createTextNode(o2));
                }
            }
            if(o3)
            {
                for(var k in o3)
                {
                    e.setAttribute(k, o3[k]);
                }
            }
            if(dd.isBool(o1) || dd.isBool(o2) || dd.isBool(o3) || dd.isBool(o4))
            {
                this.self.e.insertBefore(e, this.self.e.firstChild);
            }
            else
            {
                this.self.e.appendChild(e);
            }
            return {self:{e:e, event:{}}};
        },
        /**
         * Removes selector
         * @namespace dd.fn.remove
         * @function
         *  Removes element from DOM
         */
        remove:function()
        {
            var e = this.self.e;
            e.parentNode.removeChild(e);
        },
        /**
         * Removes contents of selector
         * @namespace dd.fn.empty
         * @function
         *  Clears inner DOM elements
         */
        empty:function()
        {
            var e = this.self.e;
            while(e.childNodes[0])
            {
                e.removeChild(e.childNodes[0]);
            }
        },
        get className()
        {
            var e = this.self.e;
            return typeof(e.className) == "object"
                    ? e.className.baseVal
                    : e.className;
        },
        set className(v)
        {
            var e = this.self.e;
            if(typeof(e.className) == "object")
            {
                return e.className.baseVal = v;
            }
            else
            {
                return e.className = v;
            }
        },
        get nodeName()
        {
            return this.self.nodeName;
        },
        /**
         * CSS Style
         * @namespace dd.fn.css
         * @function
         *  Apply CSS styles to an element
         *  @param name {string} Class name
         *  @returns element
         */
        css:function(o)
        {
            if(dd.is(o, "string"))
            {
                return this.self.e.style[o];
            }
            else
            {
                for(var i in o)
                {
                    this.self.e.style[i] = o[i];
                }
            }
            return this;
        },
        /**
         * Add's a CSS class to an element 
         * @namespace dd.fn.addClass
         * @function
         *  Add element to DOM
         *  @param name {string} Class name
         *  @returns element
         */
        addClass:function(name)
        {
            var c = dd(this).className.split(/ /);
            c.push(name);
            dd(this).className = dd.trim(c.join(" "));
            return this;
        },
        /**
         * Removes a CSS class from an element 
         * @namespace dd.fn.removeClass
         * @function
         *  Remove class from element
         *  @param name {string} Class name
         *  @returns element
         * @function
         *  Add element to DOM
         *  @param name {array} Class names
         *  @returns element
         */
        removeClass:function(o)
        {
            if(typeof o == "string")
            {
                dd(this).className = dd.trim((dd(this).className + " ").replace(new RegExp(o + " ", "g"), ""));
            }
            else
            {
                for(var i = 0; i < o.length; i++)
                {
                    dd(this).removeClass(o[i]);
                }
            }
            return this;
        },
        /**
         * Clears CSS classes on element 
         * @namespace dd.fn.clearClass
         * @function
         *  Clears out the class on element
         *  @returns element
         */
        clearClass:function()
        {
            dd(this).className = "";
            return this;
        },
        /**
         * Checks if class exists
         * @namespace dd.fn.classExists
         * @function
         *  Check class exists
         *  @param name {string} Class name
         *  @returns boolean
         * @function
         *  Check if at least one of the classes exists
         *  @param name {array} Class names
         *  @returns boolean
         */
        hasClass:function(o)
        {
            if(typeof o == "string")
            {
                return !!~(" " + dd(this).className + " ").indexOf(" " + o + " ");
            }
            else
            {
                for(var i = 0; i < o.length; i++)
                {
                    if(dd(this).hasClass(o[i]))
                    {
                        return true;
                    }
                }
                return false;
            }
        },
        /**
         * Set an element's attribute 
         * @namespace dd.fn.setAttribute
         * @function
         *  Add element to DOM
         *  @param name {string} Attribute name
         *  @param value {string} Attribute value
         */
        setAttribute:function(o1, o2)
        {
            if(typeof o1 == "string")
            {
                this.self.e.setAttribute(o1, o2);
            }
            else
            {
                for(var i in o1)
                {
                    this.self.e.setAttribute(i, o1[i]);
                }
            }
            return this;
        },
        /**
         * Get an element's attribute 
         * @namespace dd.fn.getAttribute
         * @function
         *  Add element to DOM
         *  @param name {string} Element name
         */
        getAttribute:function(name)
        {
            return this.self.e.getAttribute(name);
        },
        /**
         * Removes an attribute 
         * @namespace dd.fn.removeAttribute
         * @function
         *  Add element to DOM
         *  @param name {string} Attribute name
         */
        removeAttribute:function(name)
        {
            this.self.e.removeAttribute(name);
        },
        /**
         * Set focus to an element
         * @function
         *  Sets focus
         */
        focus:function()
        {
            this.self.e.focus();
        },
        /**
         * Set focus to an element
         * @function
         *  Sets focus
         */
        select:function()
        {
            this.self.e.select();
        },
        /**
         * Triggers an event
         * @namespace dd.fn.trigger
         * @function
         *  Triggers an event
         *  @param event {string} Event name
         * @function
         *  Triggers an event with variables
         *  @param event {string} Event name
         *  @param variables {object} Variable scope to pass
         */
        trigger:function(n, s)
        {
            if("event" in this.self)
            {
                var t = this.self.event;
                var f = {self:this.self};
                dd.combine(f, s || {});
                dd.combine(f, this.self._s);
                for(var i in t[n])
                {
                    t[n][i].call(f);
                }
            }
            return this;
        },
        /**
         * Apply events to objects
         * @namespace dd.fn.event
         * @function
         *  @param events {object} Events
         * @function
         *  @param events {object} Events
         *  @param scope {object} Pass into scope
         */
        event:function(o, s)
        {
            var self = this.self;
            self._s = s = s || {};
            if(!("event" in self))
            {
                self.event = {};
            }
            for(var i in o)
            {
                var t = self.event;
                if(!(i in t))
                {
                    t[i] = [];
                }
                t[i].push(o[i]);
                if(self.e !== null)
                {
                    self.e.addEventListener(i, (function(s, i, f)
                    {
                        return function(e)
                        {
                            var v = dd._e[i].call(this, e);
                            if(v)
                            {
                                dd.combine(v, s);
                                v.self = "attributes" in this ? {e:this} : this;
                                var r = f.call(v);
                                r = dd.is(r) ? !r : v.capture;
                                if(r)
                                {
                                    e.cancelBubble = true;
                                    if(e.stopPropagation)
                                    {
                                        e.stopPropagation();
                                    }
                                    if(e.preventDefault)
                                    {
                                        e.preventDefault();
                                    }
                                    else
                                    {
                                        e.returnValue = false;
                                    }
                                }
                            }
                        }
                    })(s, i, o[i]), true);
                }
            }
            return this;
        },
        /**
         * Sets or gets properties for objects
         */
        property:function(p, v)
        {
            var t = this[p];
            if(typeof(t) == "function")
            {
                return dd.is(v) ? this[p].call({set:true,get:false,value:v})
                                : this[p].call({set:false,get:true});
            }
            else
            {
                return dd.is(v) ? this[p] = v
                                : this[p];
            }
        }
    },
    /**
     * Splice a String
     * 
     */
    splice:function(s, i, n)
    {
        return (s.slice(0, i) + n + s.slice(i));
    },
    /**
     * isFunction
     * @namespace dd.isFunction
     * @function
     *  Check if variable is a function
     *  @param v {var} Variable to check
     *  @returns boolean
     */
    isFunction:function(v)
    {
        return this.is(v, "function");
    },
    /**
     * isString
     * @namespace dd.isString
     * @function
     *  Check if variable is a string
     *  @param v {var} Variable to check
     *  @returns boolean
     */
    isString:function(v)
    {
        return this.is(v, "string");
    },
    /**
     * isArray
     * @namespace dd.isArray
     * @function
     *  Check if variable is an array
     *  @param v {var} Variable to check
     *  @returns boolean
     */
    isArray:function(v)
    {
        return (v instanceof Array);
    },
    /**
     * isBool
     * @namespace dd.isBool
     * @function
     *  Check if variable is a boolean
     *  @param v {var} Variable to check
     *  @returns boolean
     */
    isBool:function(v)
    {
        return this.is(v, "boolean");
    },
    /**
     * isNumber
     * @namespace dd.isNumber
     * @function
     *  Check if variable is a number
     *  @param v {var} Variable to check
     *  @returns boolean
     */
    isNumber:function(v)
    {
        return this.is(v, "number");
    },
    /**
     * isInteger
     * @namespace dd.isInteger
     * @function
     *  Check if variable is an integer
     *  @param v {var} Variable to check
     *  @returns boolean
     */
    isInteger:function(v)
    {
        return parseInt(v, 10) === v;
    },
    /**
     * isObject
     * @namespace dd.isObject
     * @function
     *  Check if variable is an object
     *  @param v {var} Variable to check
     *  @returns boolean
     */
    isObject:function(v)
    {
        return this.is(v, "object");
    },
    /**
     * isNull
     * @namespace dd.isNull
     * @function
     *  Check if variable is null
     *  @param v {var} Variable to check
     *  @returns boolean
     */
    isNull:function(v)
    {
        return (v === null);
    },
    /**
     * Attaches JavaScript File
     * @namespace dd.fn.addJS
     * @function
     *  Attaches JavaScript File 
     *  @param file {string} File
     *  @returns element
     */
    addJS:function(file)
    {
        var e = dd(dd.head).addElement("script", {
            "type":"text/javascript",
            "src":file
        });
        return this;
    },
    /**
     * Removes JavaScript file
     * @namespace dd.fn.removeJS
     * @function
     *  Removes JavaScript file
     *  @param file {string} Element name
     *  @returns dd
     */
    removeJS:function(file)
    {
        dd(dd.head).each(function(){
            if(this.nodeName == "script")
            {
                if(this.src == file)
                {
                    dd.head.removeChild(this.self);
                }
            }
        });
        return this;
    },
    /**
     * Attach CSS stylesheet 
     * @namespace dd.fn.addCSS
     * @function
     *  Attach CSS stylesheet with screen media type
     *  @param file {string} File
     *  @returns dd
     * @function
     *  Attach CSS stylesheet with media type
     *  @param file {string} File
     *  @param media {string} Media
     *  @returns dd
     */
    addCSS:function(file, media)
    {
        media = media || "screen";
        var e = dd(dd.head).addElement("link", {
            "type":"text/css",
            "screen":media,
            "rel":"stylesheet",
            "href":file
        });
        return this;
    },
    /**
     * Remove CSS stylesheet 
     * @namespace dd.fn.removeCSS
     * @function
     *  Remove CSS stylesheet
     *  @param file {string} File
     *  @returns dd
     */
    removeCSS:function(file)
    {
        dd(dd.head).each(function(){
            if(this.nodeName == "link")
            {
                if(this.href == file)
                {
                    dd.head.removeChild(this.self);
                }
            }
        });
        return this;
    },
    /**
     * Get object from array of namespaces
     * @namespace dd.nsToObj
     * @function
     *  Use an array of namespaces to get an object reference
     *  @param obj {object} Object, ex: dd
     *  @param namespaces {array} Namespaces, ex: ["module", "submodule"]
     * @function
     *  Use an string to get an object reference
     *  @param obj {object} The object, ex: dd
     *  @param namespace {string} Namespace, ex: "module" or "module.submodule"
     */
    nsToObj:function(o, a)
    {
        var s = dd.is(a);
        a = s
            ? dd.is(a, "array") ? a : a.split(".")
            : dd.is(o, "array") ? o : o.split(".");
        o = s ? o : dd;
        if(a.length > 0)
        {
            var ns = o.ns.slice(0);
            for(var i = (a[0] == "dd" ? 1 : 0); i < a.length; i++)
            {
                var m = /(.*?)([^\/]+)$/.exec(a[i])[2];
                ns.push(m);
                if(!(m in o))
                {
                    o[m] = (function(o, m){return function()
                    {
                        if(o[m].isSetup)
                        {
                            return o[m].func.apply(o[m], arguments);
                        }
                        else
                        {
                            o[m].extend.apply(o[m], arguments);
                            o[m].isSetup = true;
                        }
                        return true;
                    }})(o, m);
                    o[m].extend = dd.extend;
                    o[m].ns = ns.slice(0);
                    o[m].path = o.path;
                }
                o = o[m];
            }
        }
        return o;
    },
    captureMouse:function(c)
    {
        dd.releaseMouse();
        b = c.self ? c.self.e : c;
        if (typeof c.setCapture !== "undefined") c.setCapture();
        else {
            a = function(b) {
                var d = b;
                document.removeEventListener(b.type, a, true);
                d.captureTarget = b.target;
                c.dispatchEvent(d);
                if (a !== null) document.addEventListener(b.type, a, true);
                delete d.captureTarget;
                b.stopPropagation()
            };
            document.addEventListener("mouseover", a, true);
            document.addEventListener("mouseout", a, true);
            document.addEventListener("mousemove", a, true);
            document.addEventListener("mouseup", a, true);
            document.addEventListener("mousedown", a, true);
            document.addEventListener("click", a, true);
            document.addEventListener("dblclick", a, true)
        }
        return this
    },
    releaseMouse:function()
    {
        if (b !== null) {
            if (typeof b.releaseCapture !== "undefined") b.releaseCapture();
            else {
                document.removeEventListener("mouseover", a, true);
                document.removeEventListener("mouseout", a, true);
                document.removeEventListener("mousemove", a, true);
                document.removeEventListener("mouseup", a, true);
                document.removeEventListener("mousedown", a, true);
                document.removeEventListener("click", a, true);
                document.removeEventListener("dblclick", a, true)
            }
            b = a = null
        }
        return this
    },
    /**
     * Framework specific events
     */
    event:function()
    {
        
    },
    _e:{
        load:function(e){return {capture:false};},
        resize:function(e)
        {
            return {
                capture:false,
                screen:{
                    width:window.innerWidth,
                    height:window.innerHeight
                }
            };
        },
        scroll:function(e)
        {
            return {
                capture:false,
                scroll:{
                    height:e.target.scrollHeight,
                    top:e.target.scrollTop
                },
                screen:{
                    scrollY:window.pageYOffset,
                    width:window.innerWidth,
                    height:window.innerHeight
                }
            };
        },
        mouseover:function(e)
        {
            if(e.which){var lb = (e.which == 1);}
            else if(e.button){var lb = (e.button == 0);}
            return {
                capture:false,
                mouse:{
                    left:lb
                    }
                };
        },
        mouseout:function(e)
        {
            return {
                capture:false,
                mouse:{
                    x:e.clientX,
                    y:e.clientY
                    }
                };
        },
        mousemove:function(e)
        {
            return {
                capture:false,
                mouse:{
                    x:e.layerX,
                    y:e.layerY
                }
            };
        },
        mousedown:function(e)
        {
            if (e.which) lb = (e.which == 1);
            else if (e.button) lb = (e.button == 1);
            return {
                capture:false,
                setCapture:(function(t)
                {
                    return function()
                    {
                        dd.captureMouse(t);
                    }
                })(e.target),
                target:{self:{e:e.target}},
                currentTarget:{self:{e:e.currentTarget}},
                mouse:{
                    left:(e.which) ? (e.which == 1) : (e.button == 1),
                    right:(e.which) ? (e.which == 3) : (e.button == 2),
                    x:e.layerX, //e.pageX - this.offsetLeft,
                    y:e.layerY //se.pageY - this.offsetTop
                }
            };
        },
        mouseup:function(e)
        {
            return {
                capture:false,
                releaseCapture:(function()
                {
                    return function()
                    {
                        dd.releaseMouse();
                    }
                })(),
                target:{self:{e:e.target}},
                currentTarget:{self:{e:e.currentTarget}},
                mouse:{
                    left:(e.which) ? (e.which == 1) : (e.button == 1),
                    right:(e.which) ? (e.which == 3) : (e.button == 2),
                    x:e.layerX,
                    y:e.layerY
                }
            };
        },
        contextmenu:function(e)
        {
            return {
                capture:true,
                mouse:{
                    x:e.pageX || e.clientX + document.body.scrollLeft,
                    y:e.pageY || e.clientY + document.body.scrollTop
                }
            };
        },
        keypress:function(e)
        {
            var c = 0;
            if (e.keyCode) c = e.keyCode;
            else if (e.which) c = e.which;
            return {
                capture:false,
                scroll:{
                    height:e.target.scrollHeight
                },
                key:{
                    code:c,
                    character:String.fromCharCode(c),
                    tab:c == 9,
                    enter:c == 13,
                    ctrl:e.ctrlKey,
                    shift:e.shiftKey
                }
            };
        },
        keydown:function(e)
        {
            var c = 0;
            if (e.keyCode) c = e.keyCode;
            else if (e.which) c = e.which;
            return {
                capture:false,
                key:{
                    code:c,
                    character:String.fromCharCode(c),
                    tab:c == 9,
                    enter:c == 13,
                    ctrl:e.ctrlKey,
                    shift:e.shiftKey
                }
            };
        },
        keyup:function(e)
        {
            var c = 0;
            if (e.keyCode) c = e.keyCode;
            else if (e.which) c = e.which;
            return {
                capture:false,
                key:{
                    code:c,
                    character:String.fromCharCode(c),
                    tab:c == 9,
                    enter:c == 13,
                    ctrl:e.ctrlKey,
                    shift:e.shiftKey
                }
            };
        },
        focus:function(e)
        {
            return {capture:false};
        },
        blur:function(e)
        {
            return {capture:false};
        },
        change:function(e)
        {
            return {
                capture:true
            };
        },
        click:function(e)
        {
            return {
                capture:true,
                target:{self:{e:e.target}},
                currentTarget:{self:{e:e.currentTarget}}
            };
        },
        dblclick:function(e)
        {
            return {
                capture:true,
                target:{self:{e:e.target}},
                currentTarget:{self:{e:e.currentTarget}}
            };
        }
    },
    _dom:function()
    {
        dd.body = {self:{e:document.getElementsByTagName("body")[0]}};
        dd._ready();
        dd._readied = true;
        if(dd._noWait)
        {
            dd._load();
        }
    },
    _ns:{
        "svg":"http://www.w3.org/2000/svg"
    }
});
/**
 * Namespace for projects 
 * @namespace dd.project
 * @property
 *  Use .extend to add new project dynamically
 */
dd.extend("project", {});
/* Load Event */
window.addEventListener("load", dd._dom, false);
var a = null, // replace later, being lazy
    b = null; // really really lazy... :'(